open Graph

module StringInt = struct
  type t = string * int
end

module G = Imperative.Graph.Abstract(StringInt)

module V = struct
  module G = G
  type t = string*int*(string list)
  let name  (name,_,_) = name
  let color (_,color,_) = color
  let succl (_,_,succ_list) = List.length succ_list
end


module B = Builder.I(G)
module L = Logger.Logger(G)(V)
module S = Sort.Sort(V)

open S
open L
open V
open Graphviz.DotAttributes
open Printf

module DotInput = 
  Dot.Parse
    (B)
    (struct 
      let count = ref 1
      let node (id,_) _ = match id with
	| Dot_ast.Ident s
	| Dot_ast.Number s
	| Dot_ast.String s
	| Dot_ast.Html s -> (s,!count)
      let edge _ = ()
    end)

module Display = struct
  include G
  let vertex_name v = fst(V.label v)
  let graph_attributes _ = []
  let default_vertex_attributes v = []
  let vertex_attributes v = [`Style(`Filled);`Fillcolor(12678*(G.Mark.get v))]
  let default_edge_attributes _ = []
  let edge_attributes _ = []
  let get_subgraph _ = None
end

module DotOutput = Graphviz.Dot(Display)

module VC = Vertexcolorer.VertColorer(G)(V)

open VC


let check g = printf "check color: %b " (G.fold_vertex (fun v flg -> 
                                                       let colors = (List.map (fun vi -> G.Mark.get vi) (G.succ g v)) in                                                                                                                       
                                                       (flg && not(List.exists ((=) (G.Mark.get v))colors ))) g true)


let param_check = 
    if Array.length Sys.argv >= 3 &&  Array.length Sys.argv <= 4
    then () 
    else (print_string "Invalid count of input parameters. Two parameters expected." ;exit 1)

let g = 
    let new_g = (DotInput.parse Sys.argv.(1)) in
    let iter_f v = 
        let succ = G.succ new_g v in
        let colors = List.map (fun x ->  G.Mark.get x) succ in
        let rec get_color num = 
            if (List.exists ((=)num) colors) then (get_color (num+1)) else num in
        G.Mark.set v (get_color 0) 
    in
    G.iter_vertex iter_f new_g;
    new_g

let check_graph = G.iter_vertex (fun v -> if List.exists ((=)v) (G.succ g v) 
                                          then (print_string "bad graph. There is loop in it" ;exit 1)
                                          else () ) g

let vertexes = 
    G.fold_vertex (fun v vertexes  -> 
                       let succ_name_lst = List.map (fun v -> let (name,color) = G.V.label v in name) (G.succ g v) in
                       let (name,color) = G.V.label v in
                       (name,G.Mark.get v,succ_name_lst)::vertexes
                  ) g []

let main = 
    if debug then print_graph g;    
    let new_vertexes,eff_iter_count,all_iter_count = do_iterate vertexes in
    if debug then print_vertex_group (List.fast_sort compare_by_degree (vertex_groups new_vertexes));
    print_stat !eff_iter_count !all_iter_count;
    map g new_vertexes

let dot_output = 
    check g;
    let oc = open_out Sys.argv.(2) in  
    DotOutput.output_graph oc g;
    close_out oc                          	
